/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
//package pl;

import java.io.FileNotFoundException;
import java.io.IOException;

/**
 *
 * @author sempere
 */
public final class AnalitzadorSintactic {

    AnalitzadorLexic anna;
    private String preanalisis;
    public String acumulado = "";
    private oldToken oldToken;
    private TablaSimbolos tsimbolos;
    Simbolo sGlobalAux;
    Boolean sGlobalBool = false;
    private String sGlobalStringY = "";
    private boolean sGlobalBool2 = true;
    private oldToken globalAsig = null;
    int pirula = 0;

    public AnalitzadorSintactic(String ruta) throws FileNotFoundException, IOException, oldToken {
        anna = new AnalitzadorLexic(ruta);
        preanalisis = "";
        tsimbolos = new TablaSimbolos(null, null);
    }

    public oldToken esprem() throws IOException, oldToken {
        pirula++;
        if (oldToken != null) {
            acumulado += oldToken.token;
        }
        return anna.esprem();
    }

    public String S() throws IOException, oldToken {

        String cad = "class TradC {\n\n";
        String[] bicad = new String[2];
        Simbolo s;
        empareja("");
        if (preanalisis.equals("int") || preanalisis.equals("double") || preanalisis.equals("main")) {
            cad += SP();
            cad += "\npublic static void main(String[] args){\n";
            empareja("main");
            empareja("pari");
            empareja("pard");

            s = tsimbolos.nuevoSimbolo("main", Simbolo.METODO, Simbolo.ES_MAIN);
            bicad = BLOQUE(s);
            cad += bicad[0];
            cad += bicad[1];

            empareja("arrel");

        } else if (preanalisis.equals("EOF")) {
            throw new oldToken("ERROR4", oldToken.cadena, "'double' 'int' 'main'", oldToken.fila, oldToken.columna);
        } else {
            throw new oldToken("ERROR3", oldToken.cadena, "'double' 'int' 'main'", oldToken.fila, oldToken.columna);
        }
        cad += "\n}\n";
        return cad + "\n}";
    }

    public String SP() throws IOException, oldToken {
        String cad = "";

        if (preanalisis.equals("int") || preanalisis.equals("double")) {
            cad += FUNCION(oldToken);
            cad += SP();
        } else if (preanalisis.equals("main")) {
        } else if (preanalisis.equals("EOF")) {
            throw new oldToken("ERROR4", oldToken.cadena, "'double' 'int' 'main'", oldToken.fila, oldToken.columna);
        } else {
            throw new oldToken("ERROR3", oldToken.cadena, "'double' 'int' 'main'", oldToken.fila, oldToken.columna);
        }
        return cad;
    }

    public String FUNCION(oldToken tipo) throws IOException, oldToken {
        String cad = "";
        String[] bicad = new String[2];
        int aux;
        oldToken t;

        cad += "public static ";

        if (preanalisis.equals("int") || preanalisis.equals("double")) {

            cad += TIPO(true);
            Simbolo s;

            if (tipo.token.equals("int")) {
                aux = Simbolo.ENTERO;
            } else {
                aux = Simbolo.REAL;
            }

            if (tsimbolos.existe(oldToken.cadena)) {
                throw new oldToken("ERROR5", oldToken.cadena, oldToken.fila, oldToken.columna);
            }
            s = tsimbolos.nuevoSimbolo(oldToken.cadena, Simbolo.METODO, aux);
            cad += " " + oldToken.cadena;//tsimbolos.obtinNom(oldToken.cadena);
            t = oldToken;
            empareja("id");
            empareja("pari");
            empareja("pard");
            cad += "(){\n\n";
            bicad = BLOQUE(s);
            cad += bicad[0];
            cad += bicad[1];

        } else if (preanalisis.equals("EOF")) {
            throw new oldToken("ERROR4", oldToken.cadena, "'(' ')' 'double' 'int' identificador", oldToken.fila, oldToken.columna);
        } else {
            throw new oldToken("ERROR3", oldToken.cadena, "'(' ')' 'double' 'int' identificador", oldToken.fila, oldToken.columna);
        }
        return cad + "\n}\n";
    }

    public String TIPO(boolean funcion) throws IOException, oldToken {
        String cad = "";
        if (preanalisis.equals("int")) {
            empareja("int");
            if (funcion) {
                cad += "int";
            } else {
                cad += "Integer";
            }

        } else if (preanalisis.equals("double")) {
            empareja("double");
            if (funcion) {
                cad += "double";
            } else {
                cad += "Double";
            }
        } else if (preanalisis.equals("EOF")) {
            throw new oldToken("ERROR4", oldToken.cadena, "'double' 'int' ", oldToken.fila, oldToken.columna);
        } else {
            throw new oldToken("ERROR3", oldToken.cadena, "'double' 'int' ", oldToken.fila, oldToken.columna);
        }
        return cad;
    }

    public static String traduceOperacion(Simbolo sA, int tipoB, String cadC, int tipoC, boolean cEsObjeto, boolean esPrimero, String op) {
        String retorno = "";

    
        if(esPrimero){
            if(cEsObjeto){
               if(tipoC == Simbolo.ENTERO && sA.tipo == Simbolo.ENTERO){
                   retorno = cadC + ".intValue()";
               } else if(tipoC == Simbolo.ENTERO && sA.tipo == Simbolo.REAL){
                   retorno = cadC + ".toDouble()";
               } else if(tipoC == Simbolo.REAL && sA.tipo == Simbolo.REAL){
                   retorno = cadC + ".doubleValue()";
               } else {
                  //ERROR DE INT = DOUBLE ;
               }
            } else {
                if(tipoC == sA.tipo){
                    retorno = cadC;
                } else {
                    if(tipoC == Simbolo.ENTERO){
                        retorno = "(new Integer(" + cadC;
                    } else if (tipoC == Simbolo.REAL){
                        retorno = "(new Double(" + cadC;
                    }
                }
            }
        } else {

            if(tipoB == tipoC){
                if(cEsObjeto){
                    if(tipoC == Simbolo.ENTERO){
                        retorno = op+cadC + ".intValue()";
                    } else {
                        retorno = op+cadC + ".doubleValue()";
                    }
                } else {
                    retorno = op+cadC;
                }
            } else {
                if(tipoB == Simbolo.ENTERO && sA.tipo == Simbolo.ENTERO){
                    retorno += ")).intValue()";
                    retorno +=op+ cadC;
                } else if(tipoB == Simbolo.ENTERO && sA.tipo == Simbolo.REAL){
                    retorno += ")).toDouble()";
                    if(cEsObjeto){
                        retorno +=op+cadC + ".doubleValue()";
                    } else {
                        retorno += op+ cadC;
                    }
                } else if(tipoB == Simbolo.REAL && sA.tipo == Simbolo.REAL){
                    //retorno = ")).doubleValue()<>";
                     if(cEsObjeto){
                        retorno +=op+cadC + ".toDouble()";
                    } else {
                         
                        retorno +=op+ "(new Integer(" + cadC;
                    }
                } else {
                    if(cEsObjeto){
                         if(tipoC == Simbolo.ENTERO && sA.tipo == Simbolo.ENTERO){
                           retorno = op+cadC + ".intValue()";
                       } else if(tipoC == Simbolo.ENTERO && sA.tipo == Simbolo.REAL){
                           retorno = op+ cadC + ".toDouble()";
                       } else if(tipoC == Simbolo.REAL && sA.tipo == Simbolo.REAL){
                           retorno = op+cadC + ".doubleValue()";
                       } else {
                          //ERROR DE INT = DOUBLE ;
                       }
                    } else {
                    retorno +=op+cadC +"XZ";

                    }
                }
               

            }
        }


        return retorno;

    }

    public String[] BLOQUE(Simbolo funcionPadre) throws IOException, oldToken {

        String[] bicad = new String[2];

        if (preanalisis.equals("llavei")) {
            tsimbolos = new TablaSimbolos(tsimbolos, funcionPadre);
            empareja("llavei");
            bicad = SECINSTR();
            empareja("llaved");
            tsimbolos = tsimbolos.pop();
        } else if (preanalisis.equals("EOF")) {
            throw new oldToken("ERROR4", oldToken.cadena, "'{'", oldToken.fila, oldToken.columna);
        } else {
            throw new oldToken("ERROR3", oldToken.cadena, "'{'", oldToken.fila, oldToken.columna);
        }
        return bicad;
    }

    public String[] SECINSTR() throws IOException, oldToken {
        String cad1 = "";
        String bicad[] = new String[2];
        String bibicad[] = new String[2];
        bicad[0] = "";
        bicad[1] = "";
        bibicad[0] = "";
        bibicad[1] = "";
        if (preanalisis.equals("int") || preanalisis.equals("double")) {
            cad1 += V();
            bicad = SECINSTR();
        } else if (preanalisis.equals("id") || preanalisis.equals("llavei")) {
            bicad = INSTR();
            bibicad = SECINSTR();
        } else if (preanalisis.equals("llaved")) {
        } else if (preanalisis.equals("EOF")) {
            throw new oldToken("ERROR4", oldToken.cadena, "'{' '}' 'double' 'int' identificador", oldToken.fila, oldToken.columna);
        } else {
            throw new oldToken("ERROR3", oldToken.cadena, "'{' '}' 'double' 'int' identificador", oldToken.fila, oldToken.columna);
        }
        bicad[0] = cad1 + bicad[0] + bibicad[0];
        bicad[1] = bicad[1] + bibicad[1];
        return bicad;
    }

    public String V() throws IOException, oldToken {
        String cad = "";
        int aux;

        if (oldToken.token.equals("int")) {
            aux = Simbolo.ENTERO;
        } else {
            aux = Simbolo.REAL;
        }

        if (preanalisis.equals("int") || preanalisis.equals("double")) {
            cad += TIPO(false);
            if (tsimbolos.existe(oldToken.cadena)) {
                throw new oldToken("ERROR5", oldToken.cadena, oldToken.fila, oldToken.columna);
            }
            tsimbolos.nuevoSimbolo(oldToken.cadena, Simbolo.VAR, aux);
            cad += " " + tsimbolos.obtinNom(oldToken.cadena);
            empareja("id");
            empareja("pyc");
            cad += ";\n";
        } else if (preanalisis.equals("EOF")) {
            throw new oldToken("ERROR4", oldToken.cadena, "'double' 'int'", oldToken.fila, oldToken.columna);
        } else {
            throw new oldToken("ERROR3", oldToken.cadena, "'double' 'int'", oldToken.fila, oldToken.columna);
        }
        return cad;
    }

    public String[] INSTR() throws IOException, oldToken {
        String cad = "";
        String[] bicad = new String[2];

        Simbolo sA;
        if (preanalisis.equals("id")) {
            bicad[0] = "";
            bicad[1] = "";

            globalAsig = oldToken;
            sA = tsimbolos.busca(oldToken.cadena);
            if (sA == null) {
                throw new oldToken("ERROR6", oldToken.cadena, oldToken.fila, oldToken.columna);
            } else if (sA.esMETODO()) {
                throw new oldToken("ERROR7", oldToken.cadena, oldToken.fila, oldToken.columna);
            }

            bicad[1] += tsimbolos.obtinNom(sA.nombre);
            empareja("id");
            empareja("asig");
            bicad[1] += " = ";
            bicad[1] += EXPR(sA);
            empareja("pyc");
            bicad[1] += ";\n";
        } else if (preanalisis.equals("llavei")) {
            bicad = BLOQUE(null);
        } else if (preanalisis.equals("EOF")) {
            throw new oldToken("ERROR4", oldToken.cadena, "'{' identificador", oldToken.fila, oldToken.columna);
        } else {
            throw new oldToken("ERROR3", oldToken.cadena, "'{' identificador", oldToken.fila, oldToken.columna);
        }
        return bicad;
    }

    public String EXPR(Simbolo sA) throws IOException, oldToken {
        String cad = "";
        String cad3 = "";
        String cad4 = "";
        String cadX = "";
        boolean temp = false;
        Simbolo s = null;

        if (preanalisis.equals("id") || preanalisis.equals("entero") || preanalisis.equals("real")) {
            if (preanalisis.equals("id")) {
                s = tsimbolos.busca(oldToken.cadena);
                if (s == null) {
                    throw new oldToken("ERROR6", oldToken.cadena, oldToken.fila, oldToken.columna);
                } else if (s.esMETODO()) {
                    throw new oldToken("ERROR7", oldToken.cadena, oldToken.fila, oldToken.columna);
                }
            }
            cad3 += TERM(sA, "");
            cadX = sGlobalStringY;
            cad4 += EXPR2(sA);
            temp = sGlobalBool;
            if (!temp) {
                cad += sGlobalStringA;
            }
            cad += cad3;
            if (!temp && sGlobalBool2) {
                cad += cadX;
            }
            cad += cad4;
            if (!temp) {

                cad += sGlobalStringC;
            }
            sGlobalBool = false;
            sGlobalBool2 = true;
            sGlobalAux = null;
            sGlobalStringA = "";
            sGlobalStringC = "";
            sGlobalStringY = "";


        } else if (preanalisis.equals("EOF")) {
            throw new oldToken("ERROR4", oldToken.cadena, "entero identificador real", oldToken.fila, oldToken.columna);
        } else {
            throw new oldToken("ERROR3", oldToken.cadena, "entero identificador real", oldToken.fila, oldToken.columna);
        }
        return cad;
    }

    public String EXPR2(Simbolo sA) throws IOException, oldToken {
        String cad = "";
        String operador;
        if (preanalisis.equals("addop")) {

            operador = oldToken.cadena;
            empareja("addop");

            if (sGlobalAux != null && sGlobalAux.nombre.equals("")) {
                if (sGlobalAux.esEntero() && preanalisis.equals("entero")) {
                    sGlobalBool2 = false;
                } else if (sGlobalAux.esReal() && preanalisis.equals("real")) {
                    sGlobalBool2 = false;
                }
            }




            cad += TERM(sA, operador);
            cad += EXPR2(sA);
        } else if (preanalisis.equals("pyc")) {
            if (contFactores != 1 && !(sGlobalAux != null && (sGlobalAux.nombre.equals("") && sGlobalAux.tipo == sA.tipo))) {
                cad += pendiente;
            }
            pendiente = "";
            contFactores = 0;


        } else if (preanalisis.equals("EOF")) {
            throw new oldToken("ERROR4", oldToken.cadena, "'+' o '-' ';'", oldToken.fila, oldToken.columna);
        } else {
            throw new oldToken("ERROR3", oldToken.cadena, "'+' o '-' ';'", oldToken.fila, oldToken.columna);
        }
        return cad;
    }

    public String TERM(Simbolo sA, String operador) throws IOException, oldToken {
        String cad = "";

        if (preanalisis.equals("id") || preanalisis.equals("entero") || (preanalisis.equals("real"))) {
            cad += FACTOR(sA, sGlobalAux, operador);
            cad += TERM2(sA, sGlobalAux);
        } else if (preanalisis.equals("arrel")) {
            throw new oldToken("ERROR4", oldToken.cadena, "entero identificador real", oldToken.fila, oldToken.columna);
        } else {
            throw new oldToken("ERROR3", oldToken.cadena, "entero identificador real", oldToken.fila, oldToken.columna);
        }
        return cad;
    }

    public String TERM2(Simbolo sA, Simbolo anterior) throws IOException, oldToken {
        String cad = "";
        String operador;
        //
        if (preanalisis.equals("mulop")) {
            sGlobalStringY = cad;
            operador = oldToken.cadena;
            //cad += oldToken.cadena;
            if (!anterior.nombre.equals("")) {
                cad += pendiente;
                pendiente = "";
            }
            empareja("mulop");
            cad += FACTOR(sA, anterior, operador);
            cad += TERM2(sA, anterior);
        } else if (preanalisis.equals("addop") || preanalisis.equals("pyc")) {
        } else if (preanalisis.equals("EOF")) {
            throw new oldToken("ERROR4", oldToken.cadena, "'*' o '/' '+' o '-' ';'", oldToken.fila, oldToken.columna);
        } else {
            throw new oldToken("ERROR3", oldToken.cadena, "'*' o '/' '+' o '-' ';'", oldToken.fila, oldToken.columna);
        }
        return cad;
    }
    String sGlobalStringA = "";
    String sGlobalStringC = "";
    String pendiente = "";
    int contFactores = 0;

    public String FACTOR(Simbolo sA, Simbolo anterior, String operador) throws IOException, oldToken {
        String cad = "";
        Simbolo sB;
        contFactores++;
        sGlobalBool = false;


        if (preanalisis.equals("id")) {
            if (anterior != null && !anterior.nombre.equals("")) {
                sGlobalBool2 = true;
            }
            sB = tsimbolos.busca(oldToken.cadena);
            if (anterior != null) {
                if (!(anterior.tipo == sB.tipo && anterior.nombre.equals(""))) {
                    cad += pendiente;
                    pendiente = "";
                }
            }

            if (sB.esEntero()) {
                if (sA.esEntero() && anterior == null) {
                    cad += operador;
                    sGlobalStringA += "new Integer(";
                    cad += tsimbolos.obtinNom(oldToken.cadena);
                    pendiente = ".intValue()";


                    sGlobalBool = true;
                    sGlobalStringC += ")";
                } else if (sA.esEntero() && anterior.esEntero()) {
                    cad += ".intValue()" + operador + tsimbolos.obtinNom(oldToken.cadena);
                    pendiente = ".intValue()";

                } else if (sA.esReal() && anterior == null) {
                    sGlobalStringA += "new Double(";
                    cad += tsimbolos.obtinNom(oldToken.cadena); 
                    //pendiente = ".toDouble()";//
                    sGlobalStringY = ".toDouble()";

                    sGlobalStringC += ")";
                } else if (sA.esReal() && anterior.esEntero()) {

                    cad += operador + tsimbolos.obtinNom(oldToken.cadena);
                    pendiente = ".intValue()";
                } else if (sA.esReal() && anterior.esReal()) {
                    cad += operador + tsimbolos.obtinNom(oldToken.cadena) + ".toDouble()";

                }
            } else if (sB.esReal()) {
                if (sA.esEntero()) {
                    throw new oldToken("ERROR8", globalAsig.cadena, globalAsig.fila, globalAsig.columna);
                }
                if (sA.esReal() && anterior == null) {
                    sGlobalStringA += "new Double(";
                    cad += tsimbolos.obtinNom(oldToken.cadena);
                    pendiente = ".doubleValue()";
                    sGlobalStringY = ".doubleValue()";
                    sGlobalBool = true;
                    sGlobalStringC += ")";
                } else if (sA.esReal() && anterior.esEntero()) {
                    cad += operador + tsimbolos.obtinNom(oldToken.cadena);
                    pendiente = ".doubleValue()";
                } else if (sA.esReal() && anterior.esReal()) {
                    cad += operador + tsimbolos.obtinNom(oldToken.cadena);
                    pendiente = ".doubleValue()";
                }
            }
            sGlobalAux = sB;
            empareja("id");

        } else if (preanalisis.equals("entero")) {
            if (anterior != null) {
                if (!anterior.esEntero() && !anterior.nombre.equals("")) {
                    cad += pendiente;
                    pendiente = "";
                }
            }
            if (sA.esReal() && anterior == null) {
                cad += operador;
                sGlobalStringA += "new Double(";
                cad += "(new Integer(" + oldToken.cadena;
                pendiente = ")).toDouble()";
                sGlobalStringY = ")).toDouble(";
                sGlobalStringC = ")";
                sGlobalAux = new Simbolo("", Simbolo.VAR, Simbolo.ENTERO, null);
            } else if (sA.esEntero() && anterior == null) {
                cad += operador;
                sGlobalStringA += "new Integer(";
                cad += oldToken.cadena;
                sGlobalStringC += ")";
                sGlobalAux = new Simbolo("", Simbolo.VAR, Simbolo.ENTERO, null);
            } else if (sA.esReal() && anterior.esEntero()) {
                cad += operador;
                cad += oldToken.cadena;
                sGlobalAux = new Simbolo("", Simbolo.VAR, Simbolo.ENTERO, null);
            } else if (sA.esReal() && anterior.esReal()) {
                cad += operador;
                cad += "(new Integer(" + oldToken.cadena;
                pendiente = ")).toDouble()";
                // sGlobalStringC+=")";
                sGlobalAux = new Simbolo("", Simbolo.VAR, Simbolo.ENTERO, null);
            } else if (sA.esEntero() && anterior.esEntero()) {
                cad += operador;
                cad += oldToken.cadena;
                sGlobalAux = new Simbolo("", Simbolo.VAR, Simbolo.ENTERO, null);
            }
            empareja("entero");

        } else if (preanalisis.equals("real")) {
            if (anterior != null) {
                if (!anterior.esReal() && !anterior.nombre.equals("")) {
                    cad += pendiente;
                    pendiente = "";
                }
            }
            if (sA.esReal() && anterior == null) {
                cad += operador;
                sGlobalStringA += "new Double(";
                cad += oldToken.cadena;
                sGlobalStringC += ")";
                sGlobalAux = new Simbolo("", Simbolo.VAR, Simbolo.REAL, null);
            } else if (sA.esEntero()) {
                throw new oldToken("ERROR8", globalAsig.cadena, globalAsig.fila, globalAsig.columna);
            } else if (sA.esReal() && anterior.esEntero()) {
                if (anterior.nombre.equals("")) {
                    cad += ")";
                }
                cad += operador + oldToken.cadena;
                sGlobalAux = new Simbolo("", Simbolo.VAR, Simbolo.REAL, null);
            } else if (sA.esReal() && anterior.esReal()) {
                cad += operador;
                cad += oldToken.cadena;
                sGlobalAux = new Simbolo("", Simbolo.VAR, Simbolo.REAL, null);
            }

            empareja("real");

        } else if (preanalisis.equals("EOF")) {
            throw new oldToken("ERROR4", oldToken.cadena, "entero identificador real", oldToken.fila, oldToken.columna);
        } else {
            throw new oldToken("ERROR3", oldToken.cadena, "entero identificador real", oldToken.fila, oldToken.columna);
        }
        return cad;
    }

    private void empareja(String s) throws IOException, oldToken {

        if (s.equals(preanalisis)) {
            if (!preanalisis.equals("arrel")) {
                oldToken = esprem();
            } else {
            }
            if (oldToken != null) {
                if (oldToken.token.equals("id") && (oldToken.cadena.equals("int")) || oldToken.cadena.equals("double") || oldToken.cadena.equals("main")) {
                    oldToken.token = oldToken.cadena;
                }
                preanalisis = oldToken.token;
            } else {
                oldToken = new oldToken("EOF", "", 0, 0);
                preanalisis = oldToken.token;
            }
        } else {

            if (s.equals("arrel")) {
                s = "final de fichero";
            }
            throw new oldToken("ERROR3", oldToken.cadena, "" + convierte(s) + "", oldToken.fila, oldToken.columna);
        }
    }

    String convierte(String cad) {
        if (cad.equals("pari")) {
            return "'('";
        } else if (cad.equals("pard")) {
            return "')'";
        } else if (cad.equals("llavei")) {
            return "'{'";
        } else if (cad.equals("llaved")) {
            return "'}'";
        } else if (cad.equals("id")) {
            return "identificador";
        } else if (cad.equals("asig")) {
            return "'='";
        } else if (cad.equals("addop")) {
            return "'+' o '-'";
        } else if (cad.equals("mulop")) {
            return "'*' o '/'";
        } else if (cad.equals("pyc")) {
            return "';'";
        } else {
            return cad;
        }
    } 
}
